package com.syr.mybatis;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.syr.mybatis.policy.QueryComparePolicy;
import com.syr.mybatis.policy.QueryComparePolicyEnum;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 查询策略上下文
 *
 * @author sunyiran
 * @since 2021/1/16
 */
@Slf4j
public class QueryCompareContext {

    /**
     *  缓存对象查询策略
     */
    private static final Map<Class<?>, List<QueryCompare>> queryCompareMap = new ConcurrentHashMap<>();

    /**
     * 缓存查询比较器
     */
    protected static final Map<QueryComparePolicyEnum, QueryComparePolicy> queryComparePolicyMap = new HashMap<>();

    static {
        for (QueryComparePolicyEnum policyEnum : QueryComparePolicyEnum.values()) {
            String className = String.format("com.syr.mybatis.policy.%sComparePolicy", policyEnum.name());
            try {
                Class<?> aClass = Class.forName(className);
                queryComparePolicyMap.put(policyEnum, (QueryComparePolicy) aClass.newInstance());
            } catch (ClassNotFoundException e) {
                log.error("search class failed for {}", className, e);
                throw new RuntimeException(e.getMessage());
            } catch (IllegalAccessException | InstantiationException e) {
                log.error("create instance failed for {}", className, e);
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    protected static <E> List<QueryCompare> listQueryCompare(Class<E> eClass) {

        if (!queryCompareMap.containsKey(eClass)) {
            queryCompareMap.put(eClass, analyseQueryCompare(eClass));
        }

        return queryCompareMap.get(eClass);
    }


    /**
     * 只有在第一次解析时使用反射
     *
     * @param eClass
     * @param <E>
     * @return
     */
    private static <E> List<QueryCompare> analyseQueryCompare(Class<E> eClass) {
        List<QueryCompare> queryCompareList = Lists.newArrayList();
        Field[] fields = eClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(Boolean.TRUE);
            CompareIgnore compareIgnore = field.getDeclaredAnnotation(CompareIgnore.class);

            if (compareIgnore != null) {
                continue;
            }

            QueryFieldMapping fieldMapping = field.getDeclaredAnnotation(QueryFieldMapping.class);

            QueryCompare.QueryCompareBuilder compareBuilder = QueryCompare.builder()
                    .field(field);

            if (fieldMapping != null) {
                compareBuilder.queryComparePolicyEnum(fieldMapping.comparePolicy())
                        .needNull(fieldMapping.needNull());
                if (StringUtils.isBlank(fieldMapping.value())) {
                    compareBuilder.columnName(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()));
                } else {
                    compareBuilder.columnName(fieldMapping.value());
                }

            } else {
                compareBuilder.columnName(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()))
                        .needNull(Boolean.FALSE)
                        .queryComparePolicyEnum(QueryComparePolicyEnum.EQ);
            }
            queryCompareList.add(compareBuilder.build());
        }

        return queryCompareList;
    }
}
